namespace ScrumSprintMonitor.Wpf.Application
{
	#region #using Directives

	using System;
	using System.Windows.Threading;

	using Infrastructure;
	using Infrastructure.Configuration;

	using UI.Wpf;

	#endregion

	public class PowerManager : IDisposable
	{
		//private readonly IFreeBusyInfoConfiguration freeBusyInfoConfiguration;
		private readonly ILogger<PowerManager> logger;
		private readonly IShellLayoutConfiguration shellLayoutConfiguration;
		private DispatcherTimer dispatcherTimer;
		//private ServiceController powerSavingServiceController;

		public PowerManager(IFreeBusyInfoConfiguration freeBusyInfoConfiguration, IShellLayoutConfiguration shellLayoutConfiguration,
		                    ILogger<PowerManager> logger)
		{
			if (freeBusyInfoConfiguration == null)
			{
				throw new ArgumentNullException("freeBusyInfoConfiguration");
			}
			if (shellLayoutConfiguration == null)
			{
				throw new ArgumentNullException("shellLayoutConfiguration");
			}
			if (logger == null)
			{
				throw new ArgumentNullException("logger");
			}

			//this.freeBusyInfoConfiguration = freeBusyInfoConfiguration;
			this.shellLayoutConfiguration = shellLayoutConfiguration;
			this.logger = logger;
		}

		public void Start()
		{
			if (this.dispatcherTimer != null)
			{
				throw new InvalidOperationException();
			}

			this.dispatcherTimer = new DispatcherTimer(TimeSpan.FromMinutes(0.25), DispatcherPriority.Normal, OnPowerManagementTimerCallback,
			                                           Dispatcher.CurrentDispatcher);
			this.dispatcherTimer.Start();
		}

		private void OnPowerManagementTimerCallback(object sender, EventArgs e)
		{
			if (this.shellLayoutConfiguration.RunningAsScreensaver)
			{
				NativeMethods.SetThreadExecutionState(NativeMethods.EXECUTION_STATE.ES_DISPLAY_REQUIRED | NativeMethods.EXECUTION_STATE.ES_SYSTEM_REQUIRED);
			}

			if (!Settings.Default.SuspendMachine)
			{
				return;
			}

			double timeLeftToSuspend = (SystemTime.Now().TimeOfDay - Settings.Default.TimeOfDayToSuspendMachine).TotalSeconds;
			//double timerIntervalInSeconds = this.dispatcherTimer.Interval.TotalSeconds;

			//if (this.powerSavingServiceController == null && Settings.Default.WakeUpMachine)
			//{
			//    if (timeLeftToSuspend >= -(timerIntervalInSeconds * 3.0))
			//    {
			//        try
			//        {
			//            var nextWakeUpTime = GetNextWakeUpTime();

			//            this.powerSavingServiceController = StartPowerSavingService(nextWakeUpTime);

			//            if (this.powerSavingServiceController == null)
			//            {
			//                this.logger.Error("Could not start Power Saving Agent Service in order to wake up the machine at {1}.", nextWakeUpTime);
			//            }
			//        }
			//        catch (Exception ex)
			//        {
			//            this.logger.Error(ex, "Found an exception when trying to launch Power Saving Agent Service.");
			//            throw;
			//        }
			//    }
			//}

			if (timeLeftToSuspend >= 0 && timeLeftToSuspend <= this.dispatcherTimer.Interval.TotalSeconds + 10.0)
			{
				this.logger.Debug("Suspending the machine...");
				NativeMethods.SetSuspendState(false, false, false);
			}
		}

		//private ServiceController StartPowerSavingService(DateTime nextWakeUpTime)
		//{
		//    this.logger.Debug("Starting Power Saving Agent Service in order to wake up the machine at {1}...", nextWakeUpTime);

		//    var service = new ServiceController("ScrumSprintMonitor.PowerSavingService");

		//    service.Start(new[] {nextWakeUpTime.ToUniversalTime().Ticks.ToString(NumberFormatInfo.InvariantInfo)});
		//    service.WaitForStatus(ServiceControllerStatus.Running);

		//    this.logger.Debug("Power Saving Agent Service is now running...");

		//    return service;
		//}

		//private DateTime GetNextWakeUpTime()
		//{
		//    var now = SystemTime.Now();
		//    //return now.AddMinutes(1.0);
		//    var nextWakeUpTime = now.Date.Add(Settings.Default.TimeOfDayToWakeUpMachine);
		//    bool excludeWeekends = this.freeBusyInfoConfiguration.ExcludeWeekends;
		//    for (;; nextWakeUpTime = nextWakeUpTime.AddDays(1.0))
		//    {
		//        bool validWakeUpTime = true;
		//        if (excludeWeekends)
		//        {
		//            if (nextWakeUpTime.DayOfWeek == DayOfWeek.Saturday || nextWakeUpTime.DayOfWeek == DayOfWeek.Sunday)
		//            {
		//                validWakeUpTime = false;
		//            }
		//        }
		//        if (nextWakeUpTime < now)
		//        {
		//            validWakeUpTime = false;
		//        }
		//        if (validWakeUpTime)
		//        {
		//            break;
		//        }
		//    }

		//    return nextWakeUpTime;
		//}

		#region Implementation of IDisposable

		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		private void Dispose(bool disposing)
		{
			if (disposing)
			{
				this.logger.Debug("Disposing...");

				//if (this.powerSavingServiceController != null)
				//{
				//    if (this.powerSavingServiceController.Status != ServiceControllerStatus.Stopped)
				//    {
				//        this.powerSavingServiceController.Stop();
				//        this.powerSavingServiceController.WaitForStatus(ServiceControllerStatus.Stopped);
				//    }
				//    this.powerSavingServiceController.Dispose();
				//    this.powerSavingServiceController = null;
				//}
				if (this.dispatcherTimer != null)
				{
					this.dispatcherTimer.Stop();
					this.dispatcherTimer = null;
				}
			}
		}

		#endregion
	}
}